#include "Rational.h"

ostream& operator<< (ostream& out, const Rational& rat)
{
    if (rat.numerator == 0)
        out << 0;
    else
    {
        if (rat.is_signed)
            out << "-";

        out << rat.num ();

        if (rat.denom () != 1)
            out << "/" << rat.denom ();
    }

    return out;
}

Rational::Rational (int re, int im)
{
    numerator = 1;
    denominator = 1;
    set_numerator (re);
    set_denominator (im);
}

const Rational Rational::operator+ (const Rational& second) const
{
    return Rational (num () * second.denom () + second.num () * denom (),
                     denom ()  * second.denom ());
}
    
const Rational Rational::operator- (const Rational& second) const
{
    return Rational (num () * second.denom () - second.num () * denom (),
                     denom ()  * second.denom ());
}

const Rational Rational::operator* (const Rational& second) const
{
    return Rational (num () * second.num (), denom () * second.denom ());
}

const Rational Rational::operator/ (const Rational& second) const
{
    return Rational (num () * second.denom (), denom () * second.num ());
}


void Rational::set_numerator (int a)
{
    numerator = a;
    reduce ();
}
    
void Rational::set_denominator (int b)
{
    if (b == 0)
        denominator = 1;
    else
        denominator = b;

    reduce ();
}

int Rational::num () const
{
    return numerator;
}

int Rational::denom () const
{
    return denominator;
}

double Rational::decimal () const
{
    double tmp = static_cast<double> (numerator)/denominator;
    if (is_signed)
        return -tmp;
    else
        return tmp;
}

void Rational::reduce ()
{
    if (numerator == 0)
    {
        is_signed = false;
        denominator = 1;
        return;
    }

    if (denominator == 0) denominator = 1;
    if ((numerator < 0 && denominator < 0) || 
        (numerator > 0 && denominator > 0))
        is_signed = false;
    else if ((numerator < 0 && denominator > 0) || 
             (numerator > 0 && denominator < 0))
        is_signed = true;

    numerator = ::abs (numerator);
    denominator = ::abs (denominator);

    int gcd_num = gcd (numerator, denominator);
    numerator /= gcd_num;
    denominator /= gcd_num;
}

Rational Rational::abs () const
{
    Rational tmp (*this);
    tmp.is_signed = false;
    return tmp;
}

int Rational::gcd (int a, int b)
{
    if (a < b) swap(a,b);
    while (1) {
        if (a % b == 0) 
            return b;
        else {
            int foo = b;
            b = a % b;
            a = foo;
        }
    }
    return b;
}

